package com.rzjm.api.netty.water;

import com.rzjm.api.service.IDeviceWaterService;
import com.rzjm.api.util.DateUtils;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPromise;
import io.netty.util.AttributeKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.Calendar;
import java.util.Date;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

@Component
public class NettyUtil {
    private static final Logger LOGGER = LoggerFactory.getLogger(NettyUtil.class);

    // 设备 在线状态监测频率  最后的心跳时间 超过90秒 离线
    public static Integer timeOut = 90;
    /**
     *  记录客户端
     */
    public static final Map<Integer, Channel> CHANNEL_HANDLER_CONTEXT_MAP = new ConcurrentHashMap<>();

    public static final Map<Long, ResponseData> SYNC_RESPONSEDATA_MAP = new ConcurrentHashMap<>();

    public static final AtomicInteger CONNECTION_COUNT = new AtomicInteger(0);
    private static IDeviceWaterService devicesService;
//    private static IDeviceOnOffLinesService deviceOnOffLinesService;


    @Autowired
    public void setDevicesService(IDeviceWaterService devicesService) {
        NettyUtil.devicesService = devicesService;
    }

//    @Autowired
//    public void setDeviceOnOffLinesService(IDeviceOnOffLinesService deviceOnOffLinesService) {
//        NettyUtil.deviceOnOffLinesService = deviceOnOffLinesService;
//    }

    /**
     * 判断操作系统类型
     *
     * @return 返回判断结果，如果是linux 系统返回 true
     */
    static boolean isLinux() {
        String osName = System.getProperty("os.name");
        return osName.toLowerCase().contains("linux");
    }

    public static String getRemoteAddress(ChannelHandlerContext ctx) {
        return ctx.channel().remoteAddress().toString();
    }

    /**
     * 获取信道
     */
    public static Channel getChannel(Integer deviceId) {
        if (NettyUtil.CHANNEL_HANDLER_CONTEXT_MAP.containsKey(deviceId)) {
            return NettyUtil.CHANNEL_HANDLER_CONTEXT_MAP.get(deviceId);
        }
        return null;
    }

    public static boolean isOnline(Integer deviceId) {
        return NettyUtil.CHANNEL_HANDLER_CONTEXT_MAP.containsKey(deviceId);
    }
    /**
     * 获取信道 ChannelPromise 用于同步通信
     */
    public static ChannelPromise getChannelPromise(Integer deviceId) {
        Channel channel = getChannel(deviceId);
        return channel == null ? null : channel.newPromise();
    }

    /**
     * 移除信道
     */
    public static void removeChannel(ChannelHandlerContext ctx) {
        LOGGER.info("{}断开连接", ctx.channel().id().asLongText());
        // 对应上文获取设备ID
        Integer deviceId = (Integer) ctx.channel().attr(AttributeKey.valueOf("deviceId")).get();
        // 设备上线时，如果没有向服务器上报信息，那么这个链接就不知道对应的deviceId，channel链接不会存储到CHANNEL_HANDLER_CONTEXT_MAP，也就没必要删除。
        if (deviceId != null) {
            // 删除该映射
            CHANNEL_HANDLER_CONTEXT_MAP.remove(deviceId);
            // 设备离线
            deviceOffline(deviceId);
        }
    }


    public static void autoDelChannel(ChannelHandlerContext ctx){
        LOGGER.info("{}断开连接", ctx.channel().id().asLongText());
        // 对应上文获取设备ID
        Integer deviceId = (Integer) ctx.channel().attr(AttributeKey.valueOf("deviceId")).get();
        Date lastDate = (Date) ctx.channel().attr(AttributeKey.valueOf("lastDate")).get();
        // 设备上线时，如果没有向服务器上报信息，那么这个链接就不知道对应的deviceId，channel链接不会存储到CHANNEL_HANDLER_CONTEXT_MAP，也就没必要删除。
        if (deviceId != null) {
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(lastDate);
            calendar.add(Calendar.SECOND, timeOut);
            long lastTime = calendar.getTimeInMillis();//最后连接时间，加上5分钟
            long nowTime = new Date().getTime();//当前时间
            if(nowTime >= lastTime) {//如果当前时间  要大于
                // 删除该映射
                CHANNEL_HANDLER_CONTEXT_MAP.remove(deviceId);
                // 设备离线
                deviceOffline(deviceId);
            }
        }
    }


    /**
     * 存储设备链接
     * 当设备上报数据时，带上了设备标识，此时会将链接存储起来，将来下发到设备时使用。
     * 例如发送给某设备消息，只要跟据设备Id查询链接即可getChannel(Integer deviceId)
     *
     * @param ctx
     * @param deviceId
     */
    public static void addChannel(ChannelHandlerContext ctx, Integer deviceId) {
        if (deviceId == null) {
            LOGGER.error("deviceId为空，不存储该channel");
            return;
        }
        Channel channelOld = CHANNEL_HANDLER_CONTEXT_MAP.get(deviceId);
        //没有存储该channel或旧的channelId与当前的channelId不一致时，需要更新channel
        if (channelOld == null || !(channelOld.id().asLongText()).equals(ctx.channel().id().asLongText())) {
            LOGGER.info("{}建立连接", ctx.channel().id().asLongText());
            // 使用自带Attribute类
            ctx.channel().attr(AttributeKey.valueOf("deviceId")).set(deviceId);
            ctx.channel().attr(AttributeKey.valueOf("lastDate")).set(new Date());
            // Map映射
            CHANNEL_HANDLER_CONTEXT_MAP.put(deviceId, ctx.channel());
            deviceOnline(deviceId);
        }
    }


    /**
     * 设备状态改为离线
     *
     * @param deviceId
     */
    private static void deviceOffline(Integer deviceId) {
        try{
            Optional.ofNullable(devicesService.findById(deviceId))
                .ifPresent(d -> {
                    LocalDateTime nowLd = LocalDateTime.now();
                    Date nowDate = DateUtils.toDate(nowLd);
                    d.setOnlineState(0);
                    d.setLastOfflineTime(nowDate);
                    devicesService.updateById(d);
//                    DeviceOnOffLines deviceOnOffLines = new DeviceOnOffLines();
////                deviceOnOffLines.setDeviceId(String.valueOf(deviceId));
//                    deviceOnOffLines.setDeviceId(deviceId);
//                    deviceOnOffLines.setStatus(0L);
//                    deviceOnOffLines.setTime(nowLd.atZone(ZoneId.systemDefault()).toInstant().getEpochSecond());
//                    deviceOnOffLines.setCreatedAt(nowDate);
//                    deviceOnOffLines.setUpdatedAt(nowDate);
//                    LambdaUpdateWrapper<DeviceOnOffLines> updateWrapper = Wrappers.<DeviceOnOffLines>lambdaUpdate()
//                        .eq(DeviceOnOffLines::getCreatedAt, nowDate)
//                        .eq(DeviceOnOffLines::getDeviceId, deviceId)
//                        .eq(DeviceOnOffLines::getStatus, 0L);
//                    deviceOnOffLinesService.saveOrUpdate(deviceOnOffLines, updateWrapper);

                    // TODO socket推送
//                    JSONObject socketDataJ = JSONUtil.createObj();
//                    socketDataJ.set("id", deviceId);
//                    socketDataJ.set("loginStatus", 0);
//                    String data = JSONUtil.toJsonStr(socketDataJ);
//                    webSocketService.sendSocketMessageToAll2(d, data,"deviceOnline");
                });
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    private static void deviceOnline(Integer deviceId) {
        try{
            Optional.ofNullable(devicesService.findById(deviceId))
                .ifPresent(d -> {
                    LocalDateTime nowLd = LocalDateTime.now();
                    Date nowDate = DateUtils.toDate(nowLd);
                    d.setOnlineState(1);
                    d.setLastOnlineTime(nowDate);
                    devicesService.updateById(d);
//                    DeviceOnOffLines deviceOnOffLines = new DeviceOnOffLines();
////                deviceOnOffLines.setDeviceId(String.valueOf(deviceId));
//                    deviceOnOffLines.setDeviceId(deviceId);
//                    deviceOnOffLines.setStatus(1L);
//                    deviceOnOffLines.setTime(nowLd.atZone(ZoneId.systemDefault()).toInstant().getEpochSecond());
//                    deviceOnOffLines.setCreatedAt(nowDate);
//                    deviceOnOffLines.setUpdatedAt(nowDate);
//                    LambdaUpdateWrapper<DeviceOnOffLines> updateWrapper = Wrappers.<DeviceOnOffLines>lambdaUpdate()
//                        .eq(DeviceOnOffLines::getCreatedAt, nowDate)
//                        .eq(DeviceOnOffLines::getDeviceId, deviceId)
//                        .eq(DeviceOnOffLines::getStatus, 1L);
//                    deviceOnOffLinesService.saveOrUpdate(deviceOnOffLines, updateWrapper);
                });
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    /****
     * 获取13字节的随机字符串
     * @return 13字节的随机字符串
     */
//    public static String getRandomStrLength13() {
//        long nextLong = atomicLong.addAndGet(1L);
//        return StringUtils.leftPad(Long.toHexString(nextLong), 26, '0');
//    }
}
